#include "head.h"
#define SALT_PREFIX "$6$"    // SHA-512 前缀
#define SALT_SUFFIX "$"      // 自定义结尾符号
#define RANDOM_LENGTH 8      // 8 个随机字符

// 生成随机盐值的函数
void generate_salt(char *salt, size_t length) {
    // 可用字符集（盐值的字符集可以是字母和数字）
    const char charset[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    for (size_t i = 0; i < length; i++) {
        salt[i] = charset[rand() % (sizeof(charset) - 1)];
    }
    salt[length] = '\0'; // 添加字符串结束符
}


void create_salt(char *salt_buffer, size_t buffer_size) {
    if (buffer_size < (strlen(SALT_PREFIX) + RANDOM_LENGTH + strlen(SALT_SUFFIX) + 1)) {
        fprintf(stderr, "错误：盐值缓冲区太小\n");
        return;
    }
    char random_salt[RANDOM_LENGTH + 1];  // 用于存储 8 个随机字符
                                          // 生成 8 个随机字符的盐值
    generate_salt(random_salt, RANDOM_LENGTH);
    // 将前缀、随机字符和后缀拼接成最终的盐值
    snprintf(salt_buffer, buffer_size, "%s%s%s", SALT_PREFIX, random_salt, SALT_SUFFIX);
}




//创建加密token；

int create_token(char token[],transmit_t *transmit)
{
    // 用于存储生成的JWT字符串
    char* jwt; 

    // JWT字符串的长度
    size_t jwt_length;  

    // 初始化编码参数结构体
    struct l8w8jwt_encoding_params params;
    l8w8jwt_encoding_params_init(&params); 

    // 设置JWT使用的算法，这里使用HS512
    params.alg = L8W8JWT_ALG_HS512;  

    // 设置JWT的主要荷载部分内容:
    // 主题
    params.sub = "project name";  
    // 签发者
    params.iss = "LLL";  
    // 接收方
    params.aud = transmit->name; 
   // printf("params.aud==%s\n",params.aud);
    // token过期/有效时间(0x7fffffff:最大值-> 2038年1月19日)
    params.exp = 0x7fffffff;  
    // token签发时间
    params.iat = 0;  

    // 设置加密密钥
    params.secret_key = (unsigned char*)"LLL string token key";
    params.secret_key_length = strlen((char *)params.secret_key);

    // 输出变量
    params.out = &jwt;
    params.out_length = &jwt_length;

    // 加密
    l8w8jwt_encode(&params);
    strncpy(token,jwt,jwt_length);

    // 释放token 字符串的内存
    l8w8jwt_free(jwt);
    return 0;
}





//服务端登录逻辑；
int login_server_handler(MYSQL*mysql,int net_fd,transmit_t *transmit)
{
    srand(time(NULL));
    user_t user;
    int flag_user=200;
    int flag_user_failed=400;
    int flag_pwd_failed=100;
    char user_name[100]={0};
    char *user_password_hash;//用户密码hash后的值；
    char salt[1024]={0};
    char token[512];
    strcpy(user_name,transmit->name);
    // printf("username=%s",user_name);
    int ret2=select_user(mysql,user_name,&user);
    //printf("ret2=%d\n",ret2);
    if(ret2==-1)//说明未查询到数据；
    {
        //该用户不存在，返回一个400；
        send(net_fd,&flag_user_failed,sizeof(int),MSG_NOSIGNAL);
        return 1;
    }
    //查表拿盐；
    strcpy(salt,user.salt);
    //拼接dd盐和密码并哈希；
    user_password_hash=crypt(transmit->password,salt);
    //比对哈希后的密码和数据库查询到的密码；
    if(strcmp(user_password_hash,user.pwd_hash)==0)
    {
        //返回成功登录标记200；
        send(net_fd,&flag_user,sizeof(int),MSG_NOSIGNAL);
        //密码验证成功！用户登录，生成token并返回给用户；
        create_token(token,transmit);
        //printf("测试生成token：\n%s\n",token);
        int ret1=send(net_fd,token,sizeof(token),MSG_NOSIGNAL);
        ERROR_CHECK(ret1,-1,"send token");
        return 0;
    }else
    {
        //返回登陆失败标记100;
        send(net_fd,&flag_pwd_failed,sizeof(int),MSG_NOSIGNAL);
        return 1;//非正常退出；
    }

    return 0;
}

int register_server_handler(MYSQL*mysql,int net_fd,transmit_t*transmit)
{
    srand(time(NULL));
    int name_exit=500;
    int register_success_flag=200;
    char salt[1024]={0};
    char *password_hash;
    user_t user;
    bzero(&user,sizeof(user_t));
    int ret_user_select=select_user(mysql,transmit->name,&user);
    //返回值为0，说明该用户已经存在了；
    //返回一个注册失败的标记；
    if(ret_user_select==0)
    {
        send(net_fd,&name_exit,sizeof(int),MSG_NOSIGNAL);
        return 1;
    }
    create_salt(salt,sizeof(salt));
    //哈希密码和盐值的组合；
    password_hash=crypt(transmit->password,salt);
    send(net_fd,&register_success_flag,sizeof(int),MSG_NOSIGNAL);
    // 声明一个SQL语句缓冲区
    char insert_user[2048];

    // 构建插入语句
    sprintf(insert_user,
            "INSERT INTO user (user_name, pwd_hash, salt, file_id) VALUES ('%s', '%s', '%s', '-1')",
            transmit->name, password_hash, salt
           );
    // 执行插入操作(user)
    if(mysql_query(mysql, insert_user)) {
        fprintf(stderr, "Insert user error: %s\n", mysql_error(mysql));
        return 1; // 返回错误码
    }
    //插入file表
    //先获取user_id;
    select_user(mysql,transmit->name,&user);
    int user_id=user.user_id;
    char insert_file[2048]={0};
    sprintf(insert_file,"insert into file values(NULL,'-1','/','%d',NULL,'d','/','0','0')",
            user_id
           );
    if(mysql_query(mysql,insert_file))
    {
        fprintf(stderr,"Insert file error:%s\n",mysql_error(mysql));
        return 1;
    }
    //再查file表找到刚才插入的那一条数据的file_id;
    // 获取刚插入的 file_id
    char select_file_id[1024] = {0};
    sprintf(select_file_id, "SELECT LAST_INSERT_ID()");

    if (mysql_query(mysql, select_file_id)) {
        fprintf(stderr, "Select file_id error: %s\n", mysql_error(mysql));
        return 1;
    }
    // 获取查询结果
    MYSQL_RES *result = mysql_store_result(mysql);
    if (result == NULL) {
        fprintf(stderr, "Error fetching result: %s\n", mysql_error(mysql));
        return 1;
    }
    // 处理结果
    MYSQL_ROW row = mysql_fetch_row(result);
    int file_id = atoi(row[0]);  // 获取 file_id
    mysql_free_result(result);  // 释放查询结果

    //将查找到的file_id再次返回插入user的file_id;
    char insert_user_fileid[1024];
    sprintf(insert_user_fileid,"update user set file_id= '%d' where user_name='%s'",
            file_id,transmit->name   
           );
    if(mysql_query(mysql,insert_user_fileid))
    {
        fprintf(stderr,"update user :%s\n",mysql_error(mysql));
        return 1;
    }
    //至此，存储结束；
    //返回客户端注册成功标记；
    send(net_fd,&register_success_flag,sizeof(int),MSG_NOSIGNAL);

    return 0;


}





int decrypt_token(transmit_t*transmit,int net_fd)
{
    const char *failed_buf="token解析错误!";
    // 初始化解码参数结构体
    struct l8w8jwt_decoding_params params;
    l8w8jwt_decoding_params_init(&params);  
    // 设置JWT使用的算法，这里使用HS512
    params.alg = L8W8JWT_ALG_HS512;  
    char *str=transmit->token;

    //printf("测试：打印该用户解析出来的token：\n%s",str);
    // 填入token字符串和长度
    params.jwt = (char*)str;
    params.jwt_length = strlen(str);

    // 设置密钥
    char *key="LLL string token key";
    params.verification_key = (unsigned char*)key;
    params.verification_key_length = strlen(key);

    // 定义: 接收结果的指针和变量
    struct l8w8jwt_claim *claims = NULL;
    size_t claim_count = 0;
    enum l8w8jwt_validation_result validation_result;

    // 解码: 获得token中存储的信息
    int decode_result = l8w8jwt_decode(&params, &validation_result, &claims, &claim_count);

    // 判断是否是正确的token
    if (decode_result == L8W8JWT_SUCCESS && validation_result == L8W8JWT_VALID) {
        printf("Token解密成功：该用户是：%s\n",claims[5].value);
        strcpy(transmit->name,claims[5].value);
       // printf("测试解密token------%s\n",transmit->name);
        //printf("测试解密token------%s\n",transmit->command);
        //printf("测试解密token------%s\n",transmit->argument);
    } else {
        send(net_fd,failed_buf,strlen(failed_buf),MSG_NOSIGNAL);
        printf("Token 解析错误！\n");
        return -1;
    }

    l8w8jwt_free_claims(claims, claim_count);

    return 0;
}
